#ifndef WIN32
/* mutexes & co. */
#include <pthread.h> /*NOTE: has to be the first header to use the thread safe version of the libraries! (whyever)*/
#endif

#include "Output.h"

/* output to stdout and files*/
#include <iostream>
#include <fstream>

/* strings and string manipulation */
#include <cstring>
#include <sstream>

/*timestamps and time functions*/
#include <ctime> 

/* variable argument lists */
#include <stdarg.h>


/* function names/backtracing */
#ifndef WIN32 //backtracing does not work under Windows
	#include <execinfo.h>
#endif

#ifndef WIN32
	#include <cxxabi.h>
#endif


/* lazy boy - (improve readability) */
using std::string;
using std::ostringstream;
using std::ios_base; //that's a whole namespace
using std::cout;
using std::endl;



/**
 * The output levels to be passed to the functions. Only messages with a output level equal to or greater than
 * the one set by the main application (default: DEBUG) will be printed/logged.
 * The thought behind these levels are:
 * <pre>
 * DEBUG     - all the (debug) messages you don't want to see.
 * TESTING   - still quite a lot of messages, but significantly less
 * VERBOSE   - "normal" output (what you would expect from an app) in verbose mode
 * IMPORTANT - only messages about things that may influence the execution of the program
 * CRITICAL  - only severe errors that will most likely crash the app
 * </pre>
 * (you could copy this to a usage message)<br/>
 * Of course, this is just a suggestion (although a quite sensible one, i guess) and you could
 * make use of the levels as you seem fit.<br /> 
 **/

/** <br /> All the (debug) messages you don't want to see. */
const int Output::DEBUG		= 0; 
/** Still quite a lot of messages, but significantly less. */
const int Output::TESTING	= 1; 
/** "Normal" output (what you would expect from an app) in verbose mode. */
const int Output::VERBOSE	= 2; 
/** Only messages about things that may influence the execution of the program.  */
const int Output::IMPORTANT	= 3; 
/** Only severe errors that will most likely crash the app. */
const int Output::CRITICAL	= 4; 
/** Shut up. */
const int Output::QUIET     = 32767;

/* used for validity checking */
const int Output::highestLevel = Output::CRITICAL;

/* ========  Default values  ======== */
int Output::level = Output::DEBUG;
int Output::logLevel = Output::DEBUG;

string Output::tag = "";
string Output::applicationInfo = "[Application info has not been set.]";

string Output::logPath = ".";
string Output::fullDebugLogPath = "./debug.log";
string Output::fullErrorLogPath = "./error.log";
string Output::debugLogName = "debug.log";
string Output::errorLogName = "error.log";

std::ofstream* Output::debugLog = new std::ofstream(Output::fullDebugLogPath.c_str(), ios_base::app|ios_base::out);
std::ofstream* Output::errorLog = new std::ofstream(Output::fullErrorLogPath.c_str(), ios_base::app|ios_base::out);

#ifndef WIN32
	pthread_mutex_t Output::debugLock  = PTHREAD_MUTEX_INITIALIZER;
	pthread_mutex_t Output::errorLock  = PTHREAD_MUTEX_INITIALIZER;
	pthread_mutex_t Output::outputLock = PTHREAD_MUTEX_INITIALIZER;
#endif

bool Output::alreadyLoggedDebug	= false;
bool Output::alreadyLoggedError	= false;

bool Output::doShowParams        = false;
bool Output::doShowFunctionNames = true;
bool Output::doShowFileNames     = false;
bool Output::doShowLineNumbers   = true;
bool Output::doLog				 = true;
bool Output::doUseColors		 = true;

/* ================================== */


std::vector<string>* Output::functionNameFilter = new std::vector<string>(1, "Output::"); 






/* ============================================================================================================ */
/* ============================================================================================================ */




/**
 * Get the current output level
 * 
 * @return the current output level
 **/
int Output::getLevel(){
	return Output::level;	
}


/* ============================================================================================================ */
/*                                                SETUP METHODS                                                 */
/* ============================================================================================================ */


/**
 * Set the output level. Message/hexdump calls below this level will not be processed.
 * 
 * @param level The level
 * 
 * @see Output::setLogLevel(int)
 * @see Output::setQuiet(void)
 **/
void Output::setOutputLevel(int level){
	if (level <= Output::highestLevel || level == Output::QUIET) {
		Output::level = level;
	} else {
		cout << Output::getLevelColor(Output::CRITICAL) << Output::tag << "[ERROR] Cannot set Output Level: Invalid value" << Output::getStandardColor() << endl;
	}
}

/**
 * Set the log level. Log calls below this level will not be processed.
 * 
 * @param level The level
 * 
 * @see Output::setOutputLevel(int)
 * @see Output::setQuiet(void)
 **/
void Output::setLogLevel(int level){
	if (level <= Output::highestLevel) {
		Output::logLevel = level;
		Output::doLog = true; //if someone sets a log level, we can assume he wants to log something.
	} else {
		cout << Output::getLevelColor(Output::CRITICAL) << Output::tag << "[ERROR] Cannot set Output Level: Invalid value" << endl;
	}
}

/**
 * Tell the program to shut up (i.e. don't print anything).
 * Logging options will be unchanged.
 * 
 * @see Output::setOutputLevel(int)
 **/
void Output::setQuiet(){
	Output::level = Output::QUIET;
}

/**
 * sets the application tag to print at the beginning of each line,
 * e.g. setTag("myApp") will result in lines like:
 * [myApp] [DEBUG] some debug message
 * Enclosing brackets will be added automatically.
 * 
 * @param tag the tag to prepend each line. 
 **/
void Output::setTag(std::string tag){
	
	/* Add enclosing brackets, if the user did not already */
	if (tag.c_str()[0] != '[') {
		tag.insert(0, "[");
	}
	if (tag.c_str()[tag.length()-1] != ']') {
		tag.insert(tag.length(), "]");
	}
	
	Output::tag = tag;	
		
}

/**
 * Set the application info to be noted at the start of each logging session.
 * 
 * @param info a descriptive text (short) about the application
 **/
void Output::setApplicationInfo(std::string info){
	Output::applicationInfo = info;	
}


/**
 * Specify the path where to create log files.
 * This should (but need not) be called at the beginning of the application,
 * before the first output.
 * 
 * @param path Path to log to.
 **/
void Output::setLogPath(std::string path) {
	
#ifndef WIN32
	/* this is a deep cut in the log file system, so gain access exclusively */
	pthread_mutex_lock(&(Output::debugLock));
	pthread_mutex_lock(&(Output::errorLock));
#endif
	
		ostringstream fullDebugPath;
		ostringstream fullErrorPath;
		
		Output::logPath = path;
		
		fullDebugPath << path;
		fullErrorPath << path;
		
		/* append trailing slash, if missing */
		if (path[path.length()] != '/'){
			fullDebugPath << "/";	
			fullErrorPath << "/";	
		}
		
		fullDebugPath << Output::debugLogName;
		fullErrorPath << Output::errorLogName;
		
		Output::fullDebugLogPath = fullDebugPath.str();
		Output::fullErrorLogPath = fullErrorPath.str();
	
		/* reset logging flags, so, if this is called during the application run
		 * (whyever), the logs are started anew */
		Output::alreadyLoggedDebug = false;
		Output::alreadyLoggedError = false;
	
#ifndef WIN32
	pthread_mutex_unlock(&(Output::debugLock));
	pthread_mutex_unlock(&(Output::errorLock));
#endif
	
}







/* ============================================================================================================ */
/*                                              OUTPUT METHODS                                                  */
/* ============================================================================================================ */


/**
 * Print a simple message to stdout. The message will be prepended by tags denoting the
 * program and the output level.
 * If logging is enabled (default = yes), the message will automatically be logged.
 * This method is thread-safe, i.e. no mash-up of simultaneous calls will occur.
 * 
 * @param msg	The message string to be printed
 * @param level	The lowest output level at which this message should be printed (default: DEBUG).
 * 
 * @see Output::message(char*, int, ...)
 * @see Output::log(std::string, int)
 * @see Output::log(char*, int, ...)
 **/
void Output::message(std::string msg, int level){
	if (level >= Output::level){
		
#ifndef WIN32	
		pthread_mutex_lock(&(Output::outputLock));
#endif
			
			cout << Output::getLevelColor(level);

			cout << Output::tag;
			
			cout << Output::getLevelTag(level);
			cout << Output::getCaller() << msg << Output::getStandardColor() << endl;
			
#ifndef WIN32			
		pthread_mutex_unlock(&(Output::outputLock));
#endif
	}
	
	Output::log(msg, level);
}


/**
 * Print a simple message to stdout, printf style. The variable argument list must be given after the
 * output level. The message will be prepended by tags denoting the program and the output level.
 * If logging is enabled (default = yes), the message will automatically be logged.
 * This method is thread-safe, i.e. no mash-up of simultaneous calls will occur.
 * NOTE: only the first 250 characters of a message will be printed (You're supposed to write messages,
 * not novels, anyway).
 * 
 * @param msg	The message format string to be printed
 * @param level	The lowest output level at which this message should be printed
 * @param ...	Values for the format string
 * 
 * @see Output::message(std::string, int)
 * @see Output::log(std::string, int)
 * @see Output::log(char*, int, ...)
 **/
void Output::message(const char* msg, int level, ...){
	if (level >= Output::level || level >= Output::logLevel){
		
		va_list list;
		char output[250]; //250 chars schould be enough. You're not supposed to write novels, after all.
		
		va_start(list, level);
#ifndef WIN32
		vsnprintf(output, 250, msg, list);
#else
		_vsnprintf(output, 250, msg, list);
#endif
		va_end(list);
		
		if (level >= Output::level) {
#ifndef WIN32			
			pthread_mutex_lock(&(Output::outputLock));
#endif			
				cout << Output::getLevelColor(level);
			
				cout << Output::tag;
				
				cout << Output::getLevelTag(level);
				
				
				cout << Output::getCaller() << output << endl;
				
				cout << Output::getStandardColor();
#ifndef WIN32				
			pthread_mutex_unlock(&(Output::outputLock));
#endif			
		}
		if (level >= Output::logLevel){
			Output::log(output, level);	
		}
	}	
}

/**
 * Log a simple message. The message will be prepended by a timestamp and tags denoting the
 * program and the output level. Messages with level VERBOSE or lower will be written to
 * "debug.log", others to "error.log".
 * This will automatically be called from Output::message, but only be executed if logging is
 * enabled (default = yes)
 * 
 * @param msg	The message string to be logged
 * @param level	The lowest output level at which this message should be printed (default: DEBUG).
 * 
 * @see Output::message(char*, int, ...)
 * @see Output::message(std::string, int)
 * @see Output::log(char*, int, ...)
 **/
void Output::log(std::string msg, int level){
	if (Output::doLog && level >= Output::logLevel){
		
		ostringstream output;
		
		/* generate time stamp*/
		time_t now = time(NULL);
		string timestamp(ctime(&now));
		
		output << "[" << timestamp.substr(0, timestamp.length() -1) << "] "; //remove trailing line break
		
		output << Output::getLevelTag(level);

		output << Output::getCaller()<< msg << endl;
		
		switch (level){
			case (Output::DEBUG):
            case (Output::TESTING):
			case (Output::VERBOSE):
				writeToDebugLog(output.str());
				break;
				
			case (Output::IMPORTANT):
			case (Output::CRITICAL):
				writeToErrorLog(output.str());
				break;
		}
		
	}
}

/**
 * Log a simple message, printf style. The variable argument list must be given after the
 * output level. The message will be prepended by a timestamp and tags denoting the
 * program and the output level. Messages with level VERBOSE or lower will be written to
 * "debug.log", others to "error.log".
 * This will automatically be called from Output::message, but only be executed if logging is
 * enabled (default = yes)
 * NOTE: only the first 250 characters of a message will be logged (You're supposed to write messages,
 * not novels, anyway).
 * 
 * @param msg	The message string to be logged
 * @param level	The lowest output level at which this message should be printed (default: DEBUG).
 * @param ...	Values for the format string
 * 
 * @see Output::message(std::strin, int)
 * @see Output::message(char*, int, ...)
 * @see Output::log(std::string, int)
 **/
void Output::log(const char* msg, int level, ...){
	if (Output::doLog && level >= Output::level){
		
		va_list list;
		char output_msg[250]; //250 chars schould be enough. You're not supposed to write novels, after all.
		ostringstream output;
		
		va_start(list, level);
#ifndef WIN32
		vsnprintf(output_msg, 250, msg, list);
#else
		_vsnprintf(output_msg, 250, msg, list);
#endif
	
		va_end(list);
		
		/* generate time stamp*/
		time_t now = time(NULL);
		string timestamp(ctime(&now));
		
		output << "[" << timestamp.substr(0, timestamp.length() -1) << "] "; //remove trailing line break
		
		output << Output::getLevelTag(level);

		output << Output::getCaller()<< output_msg << endl;
		
		switch (level){
			case (Output::DEBUG):
            case (Output::TESTING):
			case (Output::VERBOSE):
				writeToDebugLog(output.str());
				break;
				
			case (Output::IMPORTANT):
			case (Output::CRITICAL):
				writeToErrorLog(output.str());
				break;
		}
	}	
}

/**
 * hexdumps a byte array (e.g. an IP packet). Width and length of each line can chosen freely.
 * Each line is preceded by the number of the byte the line starts with.
 * 
 * @param type		A descriptive string of the packet, will be printed before the hexdump
 * @param data		Byte array containing the packet data to be printed out
 * @param length	Length of the data array
 * @param width		Width (in bytes) of each line to be printed out
 * @param level		The lowest output level at which to hexdump (default: DEBUG)
 **/
void Output::hexdump(std::string type, unsigned char* data, int length, int width, int level){
    if (level >= Output::level || level >= Output::logLevel){ 	
    	
#ifndef WIN32
    	pthread_mutex_lock(&(Output::outputLock));
#endif
    	
	    	ostringstream lineBuffer;
	    	ostringstream out;
	    	ostringstream logOut;
	    	
	    	/* generate time stamp*/
	    	time_t now = time(NULL);
	    	string timestamp(ctime(&now));
	    	timestamp.assign((timestamp.substr(0, timestamp.length() -1))); // remove trailing line break
	    	
	    	out << endl;
	    	
	    	string levelText;
	    	
	        out << endl;
	        logOut << endl;
	        //lineBuffer << Output::tag;
	        
	       
	        levelText = Output::getLevelTag(level);
	
	        lineBuffer << Output::getLevelColor(level) << levelText << Output::getCaller();
	        lineBuffer << type << ": " << Output::getStandardColor() << endl;
	        
 	        out << Output::tag << lineBuffer.str();
	        logOut << "[" << timestamp << "] " << lineBuffer.str();
	        lineBuffer.str("");
	        
	        
	        lineBuffer << levelText << "length: " << std::dec << length;
	        
	
	        int line = 0;
	
	        for (int i = 0; i < length; i++){
	            if ((i % width) == 0){
	            	
	            	/*lineBuffer << " :";
	            	lineBuffer.width(4);
	            	lineBuffer.fill('0');
	            	lineBuffer << dec << (line * width);*/
	            	
					lineBuffer << endl;
					
					out << Output::tag << lineBuffer.str();
			        logOut << "[" << timestamp << "] " << lineBuffer.str();
			        lineBuffer.str("");
	             
	              	lineBuffer << levelText;
	               
	            	lineBuffer.width(4);
	            	lineBuffer.fill('0');
	            	lineBuffer << std::dec << (line * width);
	               
	            	line++;
	
	            	lineBuffer << ": ";
	            }
	            lineBuffer.width(2);
	            lineBuffer.fill('0');
	            lineBuffer << std::hex << (data[i] & 0xFF);
	            lineBuffer << " ";
	            if ((i % width) == ((width/2)-1) ) {
	            	lineBuffer << " ";
	            } 
	        }
	
			lineBuffer << endl;
			
			out << Output::tag << lineBuffer.str();
	    	logOut << "[" << timestamp << "] " << lineBuffer.str();
	    	
	    	if (level >= Output::level) {
	    		cout << out.str();
	    	}
	    	if (Output::doLog && level >= Output::logLevel) {
	    		
	    		
	    		switch (level) {
				case (Output::DEBUG):
	            case (Output::TESTING):
				case (Output::VERBOSE):
					writeToDebugLog(logOut.str());
					break;
				case (Output::IMPORTANT):
				case (Output::CRITICAL):
					writeToErrorLog(logOut.str());
					break;
				}
	    	}
#ifndef WIN32	    	
       pthread_mutex_unlock(&(Output::outputLock));
#endif
    }
    
}



/**
 * Print a trace of the current call stack with a prepended note.
 * The top n levels of the call stack may be ignored. This is useful to get rid of some
 * "overhead" functions.
 * (note: The topmost function will naturally be this one, so it will be ignored and does not
 * need to be counted in stripLevels)
 * 
 * @param note			A custom text to prepend to the backtrace
 * @param level			The lowest output level at wich to print the backtrace (default: DEBUG)
 * @param stripLevels	Number of levels of the call stack that shall be ignored (default: 0).
 * 
 * @see Output::printBacktrace(int, int)
 **/
void Output::printBacktrace(std::string note, int level, int stripLevels){
	
	if (level >= Output::level){
    	cout << Output::getLevelColor(level) << Output::tag << Output::getLevelTag(level) << note << Output::getStandardColor() << endl;
	}
	
	/* level checking will be done in the respective methods, so don't do it here */
	
	Output::log(note, level);
	
	Output::printBacktrace(level, stripLevels);
}

/**
 * Print a trace of the current call stack.
 * The top n levels of the call stack may be ignored. This is useful to get rid of some
 * "overhead" functions.
 * (note: The topmost function will nuturally be this one, so it will be ignored and does not
 * need to be counted in stripLevels)
 * 
 * @param level			The lowest output level at wich to print the backtrace (default: DEBUG)
 * @param stripLevels	Number of levels of the call stack that shall be ignored (default: 0).
 * 
 * @see Output::printBacktrace(std::string, int, int)
 * @see Output::getCaller(void)
 **/
void Output::printBacktrace(int level, int stripLevels){
	

#ifdef WIN32
	cout << "*** Backtracing is not supported under Windows ***" << endl;
#else
	
	if (level >= Output::level || level >= Output::logLevel){ 
		
		/* string buffers for each line of output */
		ostringstream line;
		ostringstream logLine;
		
		/* string buffers for output (the above buffers will be fed into these) */
		ostringstream out;
		ostringstream logOut;
		
		
		int    maxAddresses = 40;		/* buffer to store the adresses of the functions on the         */
		void*  adresses[maxAddresses];  /* call stack. We only want the topmost function after we       *
										 * skipped those functions that match any function name         *
										 * filter, so getting the 10 topmost addresses should be enough */
		
	    size_t callStackSize;
	    char** mangledFunctionNames; //the mangled function names, as returned by backtrace
	    
	    char* demangleResult;		//the demangled function name as retuned by __cxa_demangle.
									//C-String, may be 0, if demangling was not successful.
	    string demangledString;		//as above, but as a C++-string, so to have something to actually work with
	    
	    string currentFunctionName;
	    string address;	//the address of the current function
	
	    int first; 		//start index of actual demanglable function name string
		int last;  		//end     "   "   "   "   "   "   "   "   "   "   "   "  
		int addrFirst;	//start index of function address in the function name string
		int addrLast;	//end     "   "   "   "   "   "   "   "   "   "   "   "   "
		int status;/* status of demangling
					* 0: The demangling operation succeeded.
				    * 1: A memory allocation failiure occurred.
				    * 2: mangled_name is not a valid name under the C++ ABI mangling rules.
				    * 3: One of the arguments is invalid.
				    **/

		
		/* create a time stamp for logging */
		time_t now = time(NULL);
		string timestamp(ctime(&now));
		timestamp.assign((timestamp.substr(0, timestamp.length() -1))); // remove trailing line break

        /* get the function names */
		callStackSize = backtrace (adresses, maxAddresses);
		mangledFunctionNames = backtrace_symbols (adresses, callStackSize);
		
		
		/* prepare the level tag to prepend each line */
		string levelText;
		levelText = Output::getLevelTag(level);
		
		
		out << Output::tag << levelText << "Backtrace:" << endl;
		logOut << "[" << timestamp << "] " << levelText << "Backtrace:" << endl;
		
		stripLevels += 1; //skip the topmost function (i.e. this one)
		for (size_t i = stripLevels; i < callStackSize; i++){			
			
			line << Output::tag << levelText << "    ";
			logLine << "[" << timestamp << "] " << levelText << "    ";
			
			currentFunctionName = mangledFunctionNames[i];
			
			/* find the actual part of the returned string containing the demanglable function name */
			first = currentFunctionName.rfind("(_Z");
			last = currentFunctionName.rfind("+0x");
			
			/* find the part of the returned string containing the function address */
			addrFirst = currentFunctionName.rfind("[");
			addrLast = currentFunctionName.rfind("]");
			
			/* only demangle if possible */
			if (first != -1){
				
				address = currentFunctionName.substr(addrFirst, (addrLast - addrFirst) + 1);
				
				currentFunctionName = currentFunctionName.substr(first+1, last-first-1);
				
				/* see http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/namespaceabi.html */
				demangleResult = abi::__cxa_demangle(currentFunctionName.c_str(), 0, 0, &status);
				
		
				if (status == 0 && demangleResult != 0){
					demangledString = demangleResult;
					
					//NOTE: Parameters will not be removed, even if the according option is set.
					//		This is no "normal" debug output, after all
					
					line << demangledString << " " << address << endl;
					logLine << demangledString << " " << address << endl;
					
				} else {
					/* if line could not be demangled, just add the string and the function address */
					line << currentFunctionName << " " << address << endl;	
					logLine << currentFunctionName << " " << address << endl;	
				}
			} else {
				/* if line is not a possibly demanglable function after all (i.e. a C function), just add the whole line */
				line << currentFunctionName << endl;	
				logLine << currentFunctionName << endl;	
			}		
		}
		
		
		out << line.str();
		logOut << logLine.str();
    	
    	if (level >= Output::level) {
    		cout << out.str();
    	}
    	if (level >= Output::logLevel) {
    		
    		
    		switch (level) {
			case (Output::DEBUG):
            case (Output::TESTING):
			case (Output::VERBOSE):
				writeToDebugLog(logOut.str());
				break;
			case (Output::IMPORTANT):
			case (Output::CRITICAL):
				writeToErrorLog(logOut.str());
				break;
			}
    	} 

	}
	
#endif /* ifndef LINUX -> else */	
	
}

/**
 * Print the application info that was (should have been) set beforehand.
 * Since this is something usually done at startup (and bacause ist looks
 * better), not tag(s) will be prepended.
 * 
 * @see Output::setApplicationInfo(std::string)
 **/
void Output::printApplicationInfo(){
	cout << endl << Output::applicationInfo << endl << endl;
	
}


/**
 * Print a seperating line.
 * This is useful when your application logic runs in loops. This way, you can easily spot the
 * "turnaround" of a loop in the output.
 * 
 * @param level The lowest output level at which to print the line (default: DEBUG)
 * 
 * @see Output::separator(std::string, int)
 **/
void Output::separator(int level){

	Output::separator("----------------------------------------------------", level);
	
}

/**
 * Print a custom seperator.
 * This is useful when your application logic runs in loops. This way, you can easily spot the
 * "turnaround" of a loop in the output.
 * 
 * @param sep the string by which to separate.
 * @param level The lowest output level at which to print the separator (default: DEBUG)
 * 
 * @see Output::separator(int)
 **/
void Output::separator(std::string sep, int level){
	
	if (level >= Output::level){
		cout << sep << endl;	
	}	
	if (level >= Output::logLevel){
		
		ostringstream out;
		
		out << sep << endl;
		switch (level) {
			case (Output::DEBUG):
			case (Output::TESTING):
			case (Output::VERBOSE):
				writeToDebugLog(out.str());
				break;
			case (Output::IMPORTANT):
			case (Output::CRITICAL):
				writeToErrorLog(out.str());
				break;
		}
	 }
	
}







/* ============================================================================================================ */
/*                                              PRIVATE METHODS                                                  */
/* ============================================================================================================ */


/**
 * Starts a new logging session.
 * Logging sessiosn are appended to previous sessions; log files will not be overwritten.
 * A logging session start is indicated by a timestamp and an info string passed to the
 * method (this will usually be the application info string).
 * This is exclusively called by #writeToDebugLog, if and only if no session had been
 * previously started.
 * 
 * @param info The application info string
 **/
void Output::startDebugLog(std::string info) {
	
	/* this is a deep cut in the log file system, so gain access exclusively */
	/* EDIT 071214: exclusively called from #writeToDebugLog, so access is already exclusive */
	//pthread_mutex_lock(&(Output::debugLock));
	
	
	if (debugLog->is_open()) {
		debugLog->close();
	}
	
	ostringstream text;
	time_t now = time(NULL);
	string timestamp(ctime(&now));
	timestamp.assign((timestamp.substr(0, timestamp.length() -1))); // remove trailing line break
	
	/* put some space between last and current session */
	text << endl << endl;
	
	text << "***** Started logging: " << timestamp << " *****" << endl;
	text << info << endl << endl;
	
	//TODO check if path exists, otherwise create it.
	//TODO if path cannot be created, use fallback (working directory or home)
	debugLog->open(fullDebugLogPath.c_str(), ios_base::app|ios_base::out);
	*debugLog << text.str().c_str();
	debugLog->close();
	
	/* EDIT 071214: see above */
	//pthread_mutex_unlock(&(Output::debugLock));
	
}

/**
 * Starts a new logging session.
 * Logging sessiosn are appended to previous sessions; log files will not be overwritten.
 * A logging session start is indicated by a timestamp and an info string passed to the
 * method (this will usually be the application info string).
 * This is exclusively called by #writeToErrorLog, if and only if no session had been
 * previously started.
 * 
 * @param info The application info string
 **/
void Output::startErrorLog(std::string info) {
	
	/* this is a deep cut in the log file system, so gain access exclusively */
	/* EDIT 071214: exclusively called from #writeToErrorLog, so access is already exclusive */
	//pthread_mutex_lock(&(Output::errorLock));
	
	
	if (errorLog->is_open()) {
		errorLog->close();
	}
	
	ostringstream text;
	time_t now = time(NULL);
	string timestamp(ctime(&now));
	timestamp.assign((timestamp.substr(0, timestamp.length() -1))); // remove trailing line break
	
	/* put some space between last and current session */
	text << endl << endl;
	
	text << "***** Started logging: " << timestamp << " *****" << endl;
	text << info << endl << endl;
	
	//TODO check if path exists, otherwise create it.
		//TODO if path cannot be created, use fallback (working directory or home)
	errorLog->open(fullErrorLogPath.c_str(), ios_base::app|ios_base::out);
	*errorLog << text.str().c_str();
	errorLog->close();
	
	/* EDIT 071214: see above */
	//pthread_mutex_unlock(&(Output::errorLock));
	
}


/**
 * Logs a message to the debug log file (levels VERBOSE or lower).
 * Suitablity of logging (level met etc.) is not checked here, but in higher level 
 * methods.
 * This method is thread safe.
 * 
 * @param text The text to log
 **/
void Output::writeToDebugLog(std::string text){

#ifndef WIN32
	/* serialize file access.
	 * This MAY impose a bottleneck, but since logging should be quite sparse,
	 * this should not be a problem.
	 * IF you need massive debug output, I suppose you are debugging and speed
	 * is not an issue anyways */
	pthread_mutex_lock(&(Output::debugLock));
#endif
	
		if (!Output::alreadyLoggedDebug) {
			Output::alreadyLoggedDebug = true;
			Output::startDebugLog(Output::applicationInfo);
		}
		
		
		if (debugLog->is_open()) {
			debugLog->close();
		}
		
		debugLog->open(fullDebugLogPath.c_str(), ios_base::app|ios_base::out);
		*debugLog << text.c_str();
		debugLog->close();
#ifndef WIN32	
	pthread_mutex_unlock(&(Output::debugLock));
#endif
}


/**
 * Logs a message to the error log file (levels IMPORTANT and CRITICAL).
 * Suitablity of logging (level met etc.) is not checked here, but in higher level 
 * methods.
 * This method is thread safe.
 * 
 * @param text The text to log
 **/
void Output::writeToErrorLog(std::string text){

#ifndef WIN32	
	/* serialize file acces.
	 * This MAY impose a bottleneck, but if the program produces so many errors
	 * that speed is affected here, something is awfully wrong anyways */
	pthread_mutex_lock(&(Output::errorLock));
#endif
	
		if (!Output::alreadyLoggedError) {
			Output::alreadyLoggedError = true;
			Output::startErrorLog(Output::applicationInfo);
		}
		
		if (errorLog->is_open()) {
			errorLog->close();
		}
		
		errorLog->open(fullErrorLogPath.c_str(), ios_base::app|ios_base::out);
		*debugLog << text.c_str();
		errorLog->close();

#ifndef WIN32		
	pthread_mutex_unlock(&(Output::errorLock));
#endif
}




/**
 * Return the fully qualified name of the function originally calling
 * any debugging function. Works only for C++ functions, anything else
 * will be called "main".
 * <strong>In order for this to work correctly, your application has to be linked
 * using the -rdynamic flag.</strong>
 * This can be toggled by calling Output::showFunctionNames().
 * 
 * @return the fully qualified name of a function
 * 
 * @see Output::showFunctionNames(bool)
 **/
string Output::getCaller(){

#ifndef WIN32	
	string result; 
	ostringstream resultBuffer; //string buffer to built up the string to be returned
	
	if (Output::doShowFunctionNames){
		
		int    maxAddresses = 10;		/* buffer to store the adresses of the functions on the         */
		void*  adresses[maxAddresses];  /* call stack. We only want the topmost function after we       *
										 * skipped those functions that match any function name         *
										 * filter, so getting the 10 topmost addresses should be enough */
		
		/* And yes, this looks *surprisingly* similar to
		 * http://www.gnu.org/software/libc/manual/html_node/Backtraces.html */
		
		
 	    size_t callStackSize;
	    char** mangledFunctionNames; //the mangled function names, as returned by backtrace
	    
	    char* demangleResult;		//the demangled function name as retuned by __cxa_demangle.
	    							//C-String, may be 0, if demangling was not successful.
	    string demangledString;		//as above, but as a C++-string, so to have something to actually work with		
	    
	    string currentFunctionName;
	
		int first; //start index of actual demanglable function name string
		int last;  //end     "   "   "   "   "   "   "   "   "   "   "   "   
		int status;/* status of demangling
					* 0: The demangling operation succeeded.
				    * 1: A memory allocation failiure occurred.
				    * 2: mangled_name is not a valid name under the C++ ABI mangling rules.
				    * 3: One of the arguments is invalid.
				    **/
		
		bool passedFilter = false; //is function name not blocked by functionNameFilter?
								   //initialized to false, otherwise loop would not be executed
		
		
		/* get the function names */
		callStackSize = backtrace (adresses, maxAddresses);
		mangledFunctionNames = backtrace_symbols (adresses, callStackSize);
		
		
		/* The main method is not a c++ class function and will thus not be demangled,
		 * which results in a plain ugly string. So, default to a nicer name ;)
		 * (NOTE: if there's something wrong with demangling (maybe you compiled/linked
		 * without -rdynamic?), every line will start with this) */
		result = "main";
		
		for (size_t i = 0; i < callStackSize && !passedFilter; i++){
			currentFunctionName = mangledFunctionNames[i];
			
			/* find the actual part of the returned string containing the demanglable function name */
			first = currentFunctionName.rfind("(_Z");
			last = currentFunctionName.rfind("+0x");
			
			if (first != -1){ //if the name didn't start with "(_Z", it was not a C++ function name
				
				currentFunctionName = currentFunctionName.substr(first+1, last-first-1);
	
				/* see http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/namespaceabi.html */
				demangleResult = abi::__cxa_demangle(currentFunctionName.c_str(), 0, 0, &status);
		
				if (status == 0 && demangleResult != 0){
					demangledString = demangleResult;
					passedFilter = true;
					
					/* see if any filter string is met */
					for (unsigned int j = 0; j < Output::functionNameFilter->size() && passedFilter; j++){
						/* if rfind returns string::npos, the filter string is not a substring of the 
						 * current function name. Hence, if any other result is returned, the string did
						 * not pass the filter. */
						passedFilter &= ((demangledString.rfind(Output::functionNameFilter->at(j)) == string::npos));
					}
					if (passedFilter) {
						result = demangledString;
					} 
				} /* if the status of __cxa_demangle is not 0 and/or the returned string is non-existant,
				   * the result string is unchanged (=> "main").
				   * This may be because of an error, but could also relate to a plain-C function being on
				   * the call stack. An error message at this point could thus be misplaced, and will only
				   * unnecessarily clog your output.
				   * If you happen to see only "main" as the calling function all the time, this would be an
				   * indicator for an error. In that case, see if you linked using the -rdynamic flag */
					///TODO apply better "error" handling (=> print the whole string or the relevant parts of it)
			} 
		}
		
		/* remove funtion parameters, if not wanted */
		if (!(Output::doShowParams)){
			result = result.substr(0, result.find_first_of('('));	
		}
	
		resultBuffer << result << ": ";
		
		free(mangledFunctionNames);
		
		
	} else {
		resultBuffer << "";
	}
	
	return resultBuffer.str();
	
#else
	return "";
#endif
}

/**
 * Return a tag to prepend each output for a certain output level.
 * 
 * @param level The output level for which to get the level tag.
 * 
 * @return The respective level tag
 **/
string Output::getLevelTag(int level){
	
	string tag;
	
	switch (level){
		case (Output::DEBUG):
        case (Output::TESTING):
			tag = "[DEBUG] ";
			break;
		case (Output::VERBOSE):
			tag = "[NOTE]  ";
			break;
		case (Output::IMPORTANT):
			tag = "[IMPORTANT] ";
			break;
		case (Output::CRITICAL):
			tag = "[CRITICAL]  ";
			break;
	}	
	
	return tag;
}

/** 
 * Return an ANSI escape sequence to change the text color on the 
 * console. Will only work on ANSI (*nix) systems, obviously.
 * 
 * @param level The output level for which to get the color.
 * 
 * @return The respective text color.
 **/
string Output::getLevelColor(int level){
	
#ifndef WIN32
	string color;
	
	if(doUseColors){
	
		switch (level){
			case (Output::DEBUG):
	        case (Output::TESTING):
				color = "\033[0m";
				break;
			case (Output::VERBOSE):
				color = "\033[0m";
				break;
			case (Output::IMPORTANT):
				color = "\033[31m";
				break;
			case (Output::CRITICAL):
				color = "\033[31m";
				break;
		}	
	} else {
		color = "";
		
	}
	
	return color;
#else
	return "";
#endif
	
}

/**
 * Return an ANSI escape sequence to reset the console colors to default.
 * This is just for reading convenience ;)
 *  Will only work on ANSI (*nix) systems, obviously.
 * 
 * @return The escape sequence to reset the console color (\033[0m)
 **/
string Output::getStandardColor(){

#ifndef WIN32
	if(doUseColors){
		return "\033[0m";
	} else {
		return "";
	}
#else
	return "";
#endif
}


